package jmine.tec.executionlog.domain;

import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.Transient;

import jmine.tec.executionlog.dao.ExecutionLogItemDAO;
import jmine.tec.executionlog.domain.enumx.ExecutionItemStatus;
import jmine.tec.persist.annotation.DiscriminatorComment;

import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.Type;

import bancosys.tec.component.Documentation;
import bancosys.tec.utils.date.Date;

/**
 * Log de execucao do Data Digester.
 * 
 * @author Marcio Ribeiro (mmr)
 * @created Jun 19, 2008
 */
@Entity
@DiscriminatorValue("0")
@DiscriminatorComment("LOG DE EXECUCAO")
public class ExecutionLog extends AbstractExecutionLog {

    private String fileCode;

    private String fileName;

    private Date fileDate;

    private String origem;

    private Integer totalItems;

    private Integer processedItems;

    private List<ExecutionLogItem> items;

    /**
     * @return codigo do arquivo.
     */
    @Column(name = "FILE_CODE", nullable = true)
    @Documentation("CÓDIGO DA INTERFACE UTILIZADA PARA LEITURA DO ARQUIVO.")
    public String getFileCode() {
        return this.fileCode;
    }

    /**
     * Define o codigo do arquivo.
     * 
     * @param fileCode codigo do arquivo.
     */
    public void setFileCode(String fileCode) {
        this.fileCode = fileCode;
    }

    /**
     * @return the fileName
     */
    @Column(name = "FILE_NAME", nullable = true)
    @Documentation("NOME DO ARQUIVO DE INTEGRAÇÃO.")
    public String getFileName() {
        return this.fileName;
    }

    /**
     * @param fileName the fileName to set
     */
    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    /**
     * Devolve a data dos dados do arquivo.
     * 
     * @return o valor do campo fileDate
     */
    @Column(name = "FILE_DT", nullable = true)
    @Type(type = "bancosys.tec.persist.hibernate.type.DateType")
    @Documentation("DATA DE GERAÇÃO DO ARQUIVO DE INTEGRAÇÃO.")
    public Date getFileDate() {
        return this.fileDate;
    }

    /**
     * Define a data dos dados do arquivo.
     * 
     * @param fileDate o valor para o campo fileDate
     */
    public void setFileDate(Date fileDate) {
        this.fileDate = fileDate;
    }

    /**
     * @return o valor do campo origem
     */
    @Column(name = "ORIGIN", nullable = true)
    @Documentation("ORIGEM DA INTEGRAÇÃO: PODE SER SISTEMA, DATAFEEDER, INTERFACE.")
    public String getOrigem() {
        return this.origem;
    }

    /**
     * @param origem o valor para o campo origem
     */
    public void setOrigem(String origem) {
        this.origem = origem;
    }

    /**
     * XXX (mmr) : esse metodo foi criado para anotar o CASCADE usado pelo Expurgo. Nao deve ser chamado por ninguem.
     * 
     * @return lista de itens.
     */
    @SuppressWarnings("unused")
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "executionLog")
    @Cascade({ CascadeType.ALL, CascadeType.DELETE_ORPHAN })
    @Documentation("ARMAZENA AS MEMÓRIAS DE LANÇAMENTO CAIXA")
    private List<ExecutionLogItem> getPrivateItems() {
        return this.items;
    }

    /**
     * Define valor para campo items.
     * 
     * @param itemss valor para campo items.
     */
    @SuppressWarnings("unused")
    private void setPrivateItems(List<ExecutionLogItem> itemss) {
        this.items = itemss;
    }

    /**
     * @return itens de log de execucao.
     * @deprecated utilize o DAO de ExecutionLogItem, este método pode retornar itens demais para a capacidade de memória
     */
    @Transient
    @Deprecated
    public SortedSet<ExecutionLogItem> getItems() {
        ExecutionLogItemDAO dao = this.getController().getDAOFactory().getDAOByClass(ExecutionLogItemDAO.class);
        return new TreeSet<ExecutionLogItem>(dao.findByExecutionLogStatus(this, null));
    }

    /**
     * Informa se log de execucao esta acompanhando uma execucao de um processo contavel.
     * 
     * @return <code>true</code> se for contavel, <code>false</code> se nao.
     */
    @Transient
    public boolean isCountable() {
        return this.totalItems != null && this.totalItems > 0;
    }

    /**
     * @return valor do campo totalItems.
     */
    @Column(name = "TOTAL_ITEM")
    @Documentation("NÚMERO TOTAL DE ITENS CONTIDOS NO ARQUIVO DA INTEGRAÇÃO.")
    public Integer getTotalItems() {
        return this.totalItems;
    }

    /**
     * Define valor para campo totalItems.
     * 
     * @param totalItems valor para campo totalItems.
     */
    public void setTotalItems(Integer totalItems) {
        this.totalItems = totalItems;
    }

    /**
     * @return numero de itens ja processados.
     */
    @Transient
    public int getProcessedItems() {
        if (!this.isRunning()) {
            return this.getTotalItems() == null ? 0 : this.getTotalItems();
        }

        if (this.processedItems == null) {
            ExecutionLogItemDAO dao = this.getController().getDAOFactory().getDAOByClass(ExecutionLogItemDAO.class);
            this.processedItems = dao.countByExecutionLog(this);
        }
        return this.processedItems;
    }

    /**
     * @param st o status do item.
     * @return o numero de itens dessa execução com o status passado.
     */
    @Transient
    public int getNumberOfItemsWithStatus(ExecutionItemStatus st) {
        ExecutionLogItemDAO dao = this.getController().getDAOFactory().getDAOByClass(ExecutionLogItemDAO.class);
        return dao.countByExecutionLogStatus(this, st);
    }

    /**
     * @return percentual de itens ja processados.
     */
    @Transient
    public int getProcessedItemsPercentage() {
        final int cem = 100;
        int percentage = 0;
        if (this.isCountable()) {
            percentage = this.getProcessedItems() * cem / this.totalItems;
        }
        return percentage;
    }

    /**
     * @return numero de itens que ainda nao foram processados.
     */
    @Transient
    public int getRemainingItems() {
        if (this.totalItems == null) {
            return 0;
        }
        return this.totalItems - this.getProcessedItems();
    }

}
